package com.yst.webplugin.fieldhandler;

import com.yst.spring.context.SpringContext;
import com.yst.web.utils.BeanUtils;
import com.yst.web.utils.ClassUtils;
import com.yst.web.utils.JsonConverter;
import com.yst.webplugin.additional.ResultProcessor;
import com.yst.webplugin.additional.mask.MaskConfigUtil;
import com.yst.webplugin.additional.transform.TransformConfigUtil;
import com.yst.webplugin.annotation.*;
import com.yst.webplugin.loginplugin.UserUtils;
import com.yst.webplugin.util.ParamUtils;
import lombok.SneakyThrows;
import org.sagacity.sqltoy.dao.SqlToyLazyDao;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;
import java.util.Objects;

public class ModifyHandler implements IFieldHandler{
    @Override
    public boolean accept(Field field) {
        return Objects.nonNull(field.getAnnotation(Modify.class));
    }

    @SneakyThrows
    @Transactional
    @Override
    public void handle(Field field, HttpInfo httpInfo) {

        Modify modify = field.getAnnotation(Modify.class);

        Class<? extends Serializable> clazz=null;
        if (modify.modelClass()!= Default.class){
            clazz=modify.modelClass();
        }

        if (Objects.isNull(clazz)) {
            clazz= (Class<? extends Serializable>) field.getType();
        }

        Serializable model = httpInfo.getBodyAs(clazz);

        SqlToyLazyDao sqlToyLazyDao = SpringContext.getContext().getBean(SqlToyLazyDao.class);

        Serializable oldModel = sqlToyLazyDao.load(model);
        Assert.notNull(oldModel,"not find the data: "+ JsonConverter.getJsonConverter().toJSONString(model));
        BeanUtils.copyProperties(model, oldModel, modify.ignoreFields());

        ParamUtils.checkParams(oldModel,modify.validClass(),modify.validClassGroup());

        if (!modify.onBeforeSave().equals(BeforeSave.class)) {
            BeforeSave beforeSave = SpringContext.getContext().getBean(modify.onBeforeSave());
            beforeSave.beforeSave(oldModel, httpInfo);
        }

        List<Field> blist= ClassUtils.getClassFieldsByFieldClass(field.getDeclaringClass(), BeforeSave.class);
        for(Field bfield:blist){
            Object controller=SpringContext.getContext().getBean(bfield.getDeclaringClass());
            if (Objects.nonNull(controller)){
                BeforeSave beforeSave=(BeforeSave) bfield.get(controller);
                if(Objects.nonNull(beforeSave)){
                    beforeSave.beforeSave(oldModel,httpInfo);
                }
            }
        }

        if (ClassUtils.classExistsField(modify.modelClass(),modify.modifyUserIdField())) {
            BeanUtils.setFieldValue(modify.modifyUserIdField(), oldModel, UserUtils.getCurrentUserId());
        }
        if (ClassUtils.classExistsField(modify.modelClass(),modify.modifyTimeField())) {
            BeanUtils.setFieldValue(modify.modifyTimeField(), oldModel, new Date());
        }

        Object uCount=sqlToyLazyDao.updateDeeply(oldModel);


        List<Field> alist=ClassUtils.getClassFieldsByFieldClass(field.getDeclaringClass(), AfterSave.class);
        for(Field afield:alist){
            Object controller=SpringContext.getContext().getBean(afield.getDeclaringClass());
            if (Objects.nonNull(controller)){
                AfterSave afterSave=(AfterSave) afield.get(controller);
                if(Objects.nonNull(afterSave)){
                    afterSave.afterSave(oldModel,httpInfo);
                }
            }
        }

        if (!modify.onAfterSave().equals(AfterSave.class)) {
            AfterSave afterSave = SpringContext.getContext().getBean(modify.onAfterSave());
            afterSave.afterSave(oldModel, httpInfo);
        }

        if (ClassUtils.isAssignableFrom(field.getType(), Boolean.class,boolean.class)){
            httpInfo.writeResult(true);
            return;
        }

        if (ClassUtils.isAssignableFrom(field.getType(), modify.modelClass())){
            ResultProcessor resultProcessor=new ResultProcessor().addAllTransformConfig(TransformConfigUtil.fromField(field))
                    .addAllTransformConfig(TransformConfigUtil.fromClass(clazz))
                    .addAllFieldMaskConfig(MaskConfigUtil.fromField(field));
            resultProcessor.deepProcess(oldModel,modify.modelClass());
            httpInfo.writeResult(oldModel);
            return;
        }

        if (ClassUtils.isAssignableFrom(field.getType(), Long.class,long.class,Integer.class,int.class)){
            httpInfo.writeResult(uCount);
        }

    }
}
